// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Timings.cs" company="Open Trader">
//   Copyright (c) David Denis (david.denis@systemathics.com)
// </copyright>
// <summary>
//   |  Open Trader - The Open Source Systematic Trading Platform
//   |
//   |  This program is free software: you can redistribute it and/or modify
//   |  it under the terms of the GNU General Public License as published by
//   |  the Free Software Foundation, either version 2 of the License, or
//   |  (at your option) any later version.
//   |
//   |  This program is distributed in the hope that it will be useful,
//   |  but WITHOUT ANY WARRANTY; without even the implied warranty of
//   |  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   |  GNU General Public License for more details.
//   |
//   |  You should have received a copy of the GNU General Public License
//   |  along with this program.  If not, see http://www.gnu.org/licenses
//   |
//   |  Up to date informations about Open Trader can be found at :
//   |    http://opentrader.org
//   |    http://opentrader.codeplex.com
//   |
//   |  For professional services, please visit us at :
//   |    http://www.systemathics.com
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Org.OpenTrader.Framework
{
    /*
     * have a lok at System.Diagnostics.Stopwatch
     */
    #region Usings

    using System;
    using System.Runtime.InteropServices;

    #endregion

    /// <summary>
    /// The timings.
    /// </summary>
    public class Timings
    {
        #region Constants and Fields

        /// <summary>
        /// The dateinit.
        /// </summary>
        private static DateTime dateinit;

        /// <summary>
        /// The freq.
        /// </summary>
        private static double freq = Double.NaN;

        /// <summary>
        /// The tickinit.
        /// </summary>
        private static double tickinit = Double.NaN;

        #endregion

        #region Constructors and Destructors

#if BENCHMARKS
    
    
    
    
    // <summary>
    // Initializes static members of the <see cref="Timings"/> class.
    // </summary>
        static Timings()
        {

            BenchmarkingEnabled = true;

        }

#endif

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets benchmarking activation. If false BenchmarkNow and Benchmark(...) won't do anything
        /// </summary>
        public static bool BenchmarkingEnabled { get; set; }

        /// <summary>
        /// Gets BenchmarkNow.
        /// </summary>
        public static DateTime BenchmarkNow
        {
            get
            {
                if (BenchmarkingEnabled)
                {
                    return Now;
                }

                return DateTime.MinValue;
            }
        }

#if ! AnyCPU

        /// <summary>
        /// Retrieve the current time with high precision. This is far more precise than Timings.Now
        /// </summary>
        public static DateTime Now
        {
            get
            {
                double currentTick = NCount;
                if (Double.IsNaN(tickinit))
                {
                    dateinit = DateTime.Now;
                    tickinit = currentTick;
                }

                if (Double.IsNaN(freq))
                {
                    freq = NFreq;
                }

                var diff = currentTick - tickinit;
                return new DateTime(dateinit.Ticks + (long)(1000.0 * TimeSpan.TicksPerMillisecond * diff / freq));
            }
        }

        /// <summary>
        /// Gets NCount.
        /// </summary>
        private static long NCount
        {
            get
            {
                long c = 0;
                Native.QueryPerformanceCounter(out c);
                return c;
            }
        }

        /// <summary>
        /// Gets NFreq.
        /// </summary>
        private static long NFreq
        {
            get
            {
                long f = 0;
                Native.QueryPerformanceFrequency(out f);
                return f;
            }
        }

#else
        public static DateTime Now
        {
            get
            {
                return DateTime.Now;
            }
        }

#endif

        #endregion

        #region Public Methods

        /// <summary>
        /// The benchmark.
        /// </summary>
        /// <param name="what">
        /// The what.
        /// </param>
        /// <param name="v1">
        /// The v 1.
        /// </param>
        public static void Benchmark(string what, DateTime v1)
        {
#if BENCHMARKS
            if (BenchmarkingEnabled)
            {
                var v2 = Now;
                var dt = v2 - v1;

                Stdout.WriteLine(string.Format("{0} Benchmark of {1} lead to dt={2}", PrettyPrinter.Timings.Format(Now), what, dt));
            }

#endif
        }

        #endregion

#if ! AnyCPU

        /// <summary>
        /// The native.
        /// </summary>
        internal class Native
        {
            #region Public Methods

            /// <summary>
            /// The query performance counter.
            /// </summary>
            /// <param name="performanceCount">
            /// The performance count.
            /// </param>
            /// <returns>
            /// True on success.
            /// </returns>
            [DllImport("Kernel32.dll")]
            public static extern bool QueryPerformanceCounter(out long performanceCount);

            /// <summary>
            /// The query performance frequency.
            /// </summary>
            /// <param name="frequency">
            /// The frequency.
            /// </param>
            /// <returns>
            /// True on success.
            /// </returns>
            [DllImport("Kernel32.dll")]
            public static extern bool QueryPerformanceFrequency(out long frequency);

            #endregion
        }

#endif
    }
}